package com.zhima.task;

import com.zhima.data.*;
import com.zhima.function.ConfigurationIndexAssociate;
import com.zhima.panel.NewLineConfiguration;
import com.zhima.panel.RandomInDataConfiguration;
import com.zhima.util.FileUtil;

import javax.swing.*;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;

import static java.math.BigInteger.ONE;
import static java.math.BigInteger.ZERO;

/**
 * @author : 芝麻
 * @date : 2023-08-05 11:08
 **/
public class GenerateInDataTask implements Runnable {
    private final List<RandomInDataConfiguration> randomInDataConfigurations;
    private final JLabel selectedInFileOutputJLabel;
    private final int dataBarsNumber;
    private final ExecutorService executorService;

    public GenerateInDataTask(ExecutorService executorService, List<RandomInDataConfiguration> randomInDataConfigurations, JLabel selectedInFileOutputJLabel, int dataBarsNumber) {
        this.randomInDataConfigurations = randomInDataConfigurations;
        this.selectedInFileOutputJLabel = selectedInFileOutputJLabel;
        this.dataBarsNumber = dataBarsNumber;
        this.executorService = executorService;
    }

    @Override
    public void run() {
        String selectedInFileOutputPath = selectedInFileOutputJLabel.getText();
        FileUtil.ensureDirExist(selectedInFileOutputPath);
        CountDownLatch countDownLatch = new CountDownLatch(dataBarsNumber);
        for (int i = 0; i < dataBarsNumber; i++) {
            final int finalI = i + 1;
            executorService.submit(() -> {
                List<BigInteger> tempResult = new ArrayList<>();
                try (PrintWriter pw = new PrintWriter(new FileWriter(String.format("%s%stest%d.in", selectedInFileOutputPath, File.separator, finalI)))) {
                    for (RandomInDataConfiguration randomInDataConfiguration : randomInDataConfigurations) {
                        BigInteger loop = ONE;
                        int dataAssociationIndex = randomInDataConfiguration.dataAssociation();
                        if (dataAssociationIndex != -1) {
                            loop = tempResult.get(dataAssociationIndex - 1);
                        }
                        BigInteger k = ZERO;
                        while (!loop.subtract(k).equals(ZERO)) {
                            k = k.add(ONE);
                            if (randomInDataConfiguration instanceof NewLineConfiguration) {
                                pw.print('\n');
                                continue;
                            }
                            RandomDataType randomDataType = RandomDataType.valueOf(randomInDataConfiguration.getRandomDataType());
                            BigDecimal min = new BigDecimal(randomInDataConfiguration.getMin());
                            BigDecimal max = new BigDecimal(randomInDataConfiguration.getMax());
                            if (randomDataType == RandomDataType.ARRAY) {
                                Object[] randomData = (Object[]) new ArrayRandomData(
                                        min,
                                        max,
                                        randomInDataConfiguration.getMinLength(),
                                        randomInDataConfiguration.getMaxLength(),
                                        randomInDataConfiguration.getTwoDimensionMinLength(),
                                        randomInDataConfiguration.getTwoDimensionMaxLength(),
                                        randomInDataConfiguration.getArrayDimension(),
                                        randomInDataConfiguration.getArrayElementRandomDataType())
                                        .randomElement();
                                if (randomInDataConfiguration.getArrayDimension() == ArrayDimension.ONE) {
                                    if (randomInDataConfiguration.shouldPrintArrayLength()) {
                                        pw.print(randomData.length);
                                        pw.print('\n');
                                    }
                                    for (Object r : randomData) {
                                        pw.print(r);
                                        pw.print(' ');
                                    }
                                    pw.print('\n');
                                } else {
                                    Object[][] tRandomData = (Object[][]) randomData;
                                    if (randomInDataConfiguration.shouldPrintArrayLength()) {
                                        pw.print(tRandomData.length);
                                        pw.print(' ');
                                        pw.print(tRandomData[0].length);
                                        pw.print('\n');
                                    }
                                    for (Object[] randomRowData : tRandomData) {
                                        for (Object r : randomRowData) {
                                            pw.print(r);
                                            pw.print(' ');
                                        }
                                        pw.print('\n');
                                    }
                                }
                                // 数组不会被数据关联，但是需要占个位子
                                tempResult.add(null);
                                continue;
                            }
                            Object data;
                            switch (randomDataType) {
                                case INT: {
                                    data = new IntRandomData(min, max).randomElement();
                                    break;
                                }
                                case LONG: {
                                    data = new LongRandomData(min, max).randomElement();
                                    break;
                                }
                                case BIG_INTEGER: {
                                    data = new BigIntegerRandomData(min, max).randomElement();
                                    break;
                                }
                                case BOOLEAN: {
                                    data = new BooleanRandomData().randomElement();
                                    break;
                                }
                                default:
                                    throw new IllegalArgumentException("参数异常");
                            }
                            if (randomDataType != RandomDataType.BOOLEAN) {
                                tempResult.add(new BigInteger(String.valueOf(data)));
                            } else {
                                // 布尔类型不会被数据关联，但是需要占个位
                                tempResult.add(null);
                            }
                            pw.print(data);
                            pw.print(' ');
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    // 确保计数器减一
                    countDownLatch.countDown();
                }
            });
        }
        try {
            // 等到所有的in文件生成完毕
            countDownLatch.await();
            JOptionPane.showMessageDialog(null, "随机数据生成完毕！");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
